import 'package:opencv_dart/opencv_dart.dart' as cv;

class OpencvUtils {
  /// 亮度评估
  static bool isBrightness(
    cv.Mat image, {
    int? code,
    int brightnessThreshold = 100,
    double threshold = 50.0,
  }) {
    final gray = code != null ? cv.cvtColor(image, code) : cv.Mat.fromMat(image, copy: true);

    // 计算总像素数
    final totalPixels = gray.rows * gray.cols;

    // 计算亮度较高的像素数（假设亮度阈值为200）
    int brightPixels = 0;

    for (var i = 0; i < gray.rows; i++) {
      for (var j = 0; j < gray.cols; j++) {
        final pixelValue = gray.at<int>(i, j);
        if (pixelValue > brightnessThreshold) brightPixels++;
      }
    }

    // 计算亮度百分比
    final brightnessPercentage = brightPixels / totalPixels * 100;
    gray.dispose();
    return brightnessPercentage > threshold;
  }

  /// 模糊评估
  /// 采用了一种结合Sobel算子和拉普拉斯算子的方案。Sobel算子
  /// 通过计算图像灰度的空间梯度来突出边缘信息，有效地识别出图
  /// 像中的边缘特征。而拉普拉斯算子作为一种二阶导数算子，能够
  /// 检测图像中的平坦区域和边缘变化，从而突出图像的细节信息。
  /// 将这两种算子相结合，可以发挥它们各自的优势，不仅能够精确
  /// 地检测到图像的边缘，还能细致地捕捉到图像中的细节变化，从
  /// 而显著提升图像模糊检测的整体性能
  static bool isBlurry(
    cv.Mat image, {
    int? code,
    double threshold = 100.0,
  }) {
    // 将图像转换为灰度图
    final gray = code != null ? cv.cvtColor(image, code) : cv.Mat.fromMat(image, copy: true);
    // 计算拉普拉斯方差
    final fm = _computeLaplacianVariance(gray);
    // 计算Sobel梯度均值
    final sobelMean = _computeSobel(gray);
    // 计算模糊度量值，这里结合了拉普拉斯方差和Sobel均值255是参数，可以根据场景的图片进行调整
    final blurMeasure = (0.5 * fm) + (0.5 * (sobelMean - 255));
    gray.dispose();
    return blurMeasure < threshold;
  }

  static double _computeLaplacianVariance(cv.Mat gray) {
    // 计算拉普拉斯图像
    final laplacian = cv.laplacian(gray, cv.MatType.CV_64F);
    // 计算拉普拉斯图像的方差
    final ret = laplacian.variance().val[0];
    laplacian.dispose();
    return ret;
  }

  /// 计算Sobel梯度均值
  static double _computeSobel(cv.Mat gray) {
    // 计算水平和垂直方向的Sobel梯度
    final sobelx = cv.sobel(gray, cv.MatType.CV_64F, 1, 0, ksize: 5);
    final sobely = cv.sobel(gray, cv.MatType.CV_64F, 0, 1, ksize: 5);
    // 计算梯度的合成幅度 sobel = sqrt(sobelx^2 + sobely^2)
    final sobel = sobelx.mul(sobelx).add(sobely.mul(sobely)).sqrt();
    final ret = sobel.mean().val[0];
    sobel.dispose();
    return ret;
  }
}
